<?php
/**
 * Spiffy Library
 *
 * LICENSE
 *
 * This source file is subject to the new BSD license that is
 * available through the world-wide-web at this URL:
 * http://www.spiffyjr.me/license
 *
 * @category   	Spiffy
 * @package    	Spiffy_Db
 * @copyright  	Copyright (c) 2009 Kyle Spraggs. http://www.spiffyjr.me
 * @license 	http://www.spiffyjr.me/license	New BSD License
 * @author 		Kyle Spraggs <theman@spiffyjr.me>
 */

/**
 * Class to provide a select object for the Spiffy Db library.
 *
 * @category	Spiffy
 * @package		Spiffy_Db
 * @copyright  	Copyright (c) 2009 Kyle Spraggs. http://www.spiffyjr.me
 * @license 	http://www.spiffyjr.me/license	New BSD License
 */
class Spiffy_Db_Table_Select extends Zend_Db_Table_Select
{
	const THIS = false;
	const LAST_JOINED = true;
	
	protected $_lastJoined = null;
	
	/**
	 * Class constructor
	 *
	 * @param Zend_Db_Table_Abstract $adapter
	 */
	public function __construct(Zend_Db_Table_Abstract $table)
	{
		parent::__construct($table);
	}
	
	public function by($rule, $cols = array('*'), $type = 'inner')
	{
		$ref = $this->_parseRule($rule, self::THIS);
		return $this->_joinByRule($ref, $cols, $type);
	}
	
	public function with($rule, $cols = array('*'), $type = 'inner')
	{
		$ref = $this->_parseRule($rule, self::LAST_JOINED);
		return $this->_joinByRule($ref, $cols, $type);
	}
	
	public function group($clause, $tableName = null)
	{
		$table = $this->_parseTableName($tableName);
		parent::group($table . '.' . $clause);
		return $this;
	}
	
	public function order($clause, $tableName = null)
	{
		$table = $this->_parseTableName($tableName);
		parent::order($table . '.' . $clause);
		return $this;
	}
	
	public function orWhere($cond, $value = null, $tableName = null)
	{
		$table = $this->_parseTableName($tableName);
		parent::orWhere($table . '.' . $cond, $value);
		return $this;
	}
	
	public function where($cond, $value = null, $tableName = null)
	{
		$table = $this->_parseTableName($tableName);
		parent::where($table . '.' . $cond, $value);
		return $this;
	}
	
	protected function _parseRule($rule, $byPreviousParsing = false)
	{
		if (is_array($rule)) {
			$correlation = key($rule);
			$rule = current($rule);
		} else {
			$correlation = null;
		}
		
		$referenceMap = $this->getTable()->info(Spiffy_Db_Table::REFERENCE_MAP);
		
		if (isset($referenceMap[$rule])) {
			$rule = $referenceMap[$rule];
			$tableName = $this->getTable()->getRefTableName($rule['refTableClass']);
			
			if (is_null($correlation)) {
				$correlation = $tableName;
			}
			if ($byPreviousParsing === self::LAST_JOINED && !is_null($this->_lastJoined)) {
				$matchTable = $this->_lastJoined;
			} else {
				$matchTable = $this->getTable()->info(Spiffy_Db_Table::NAME);
			}
			
			if (!is_array($rule['refColumns'])) {
				$rule['refColumns'] = array($rule['refColumns']);
			}
			
			if (!is_array($rule['columns'])) {
				$rule['columns'] = array($rule['columns']);
			}
			
			if (count($rule['columns']) != count($rule['columns'])) {
				throw new Spiffy_Db_Table_Select_Exception('Column count does not match reference column count');
			}
			
			$cond = $correlation . '.' . $rule['refColumns'][0] . '=' . $matchTable . '.' . $rule['columns'][0];
			$count = count($rule['refColumns']);
			
			if ($count > 1) {
				foreach (range(1, ($count - 1)) as $key) {
					$cond .= ' AND ' . $correlation . '.' . $rule['refColumns'][$key] . '=' . $matchTable . '.' . $rule['columns'][$key];
				}
			}
			
			is_array($rule['refColumns']) ? $refColumn = $rule['refColumns'][0] : $refColumn = $rule['refColumns'];
			is_array($rule['columns']) ? $column = $rule['columns'][0] : $column = $rule['columns'];
			
			$ref = array(
				'table' => array($correlation => $tableName), 
				'cond' => $correlation . '.' . $refColumn . '=' . $matchTable . '.' . $column);
			
			return $ref;
		}
		return false;
	}
	
	protected function _parseTableName($tableName)
	{
		if (is_null($tableName) || $tableName === self::THIS) {
			$table = $this->getTable()->info(Spiffy_Db_Table::NAME);
		} else if ($tableName === self::LAST_JOINED) {
			$table = $this->_lastJoined;
		} else if (is_string($tableName)) {
			$table = $this->getTable()->getRefTableName($tableName);
		}
		return $table;
	}
	
	protected function _joinByRule($reference, $cols = array('*'), $type = 'inner')
	{
		if (false !== $reference) {
			$this->{'join' . ucfirst($type)}($reference['table'], $reference['cond'], $cols);
			$this->_lastJoined = key($reference['table']);
			return $this;
		}
		return false;
	}
}